package jobs.controller.facade;

import java.io.Serializable;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.faces.context.Flash;
import javax.faces.event.ActionEvent;
import jobs.ejb.facade.AbstractFacade;
import jobs.event.selectable.ModelSelectable;
import jobs.model.facade.EntityFacade;
import org.primefaces.context.RequestContext;
import org.primefaces.event.SelectEvent;

/**
 * Es una fachada para los controladores que lo hereden
 *
 * @author Paul Tamayo
 */
public abstract class ControllerFacade<T extends EntityFacade> implements Serializable {

    /**
     * Muestra el nombre de la entidad
     */
    private String entityName;
    /**
     * Clase Entidad
     */
    private Class<T> entity;
    /**
     * Nos permite verificar si los botones de editar y eliminar aparecen
     * deshabilitados.
     */
    private boolean disableButtons = true;
    /**
     * Permite especificar el nombre del cuadro de dialogo para nuevo y editar.
     */
    private String titleDialog;
    /**
     * Especifica la entidad seleccionada.
     */
    private T selected;
    /**
     * Listado las filas de la entidad seleccionada.
     */
    private List<T> list;
    /**
     * El modelo de datos seleccionado para iterar en el listado de la vista.
     */
    private ModelSelectable<T> selectable;

    public ControllerFacade(Class<T> entity) {
        this.entity = entity;
    }

    public boolean isDisableButtons() {
        return disableButtons;
    }

    public void setDisableButtons(boolean disableButtons) {
        this.disableButtons = disableButtons;
    }

    public String getTitleDialog() {
        return titleDialog;
    }

    public T getSelected() {
        return selected;
    }

    public void setSelected(T selected) {
        this.selected = selected;
    }

    public ModelSelectable getSelectable() {
        return new ModelSelectable(getList());
    }

    public List<T> getList() {
        return getFacade().findAll();
    }

    /**
     * Permite guardar una nueva entidad o editar la entidad seleccionada.
     *
     * @param event
     */
    public void edit(ActionEvent event) {
        FacesMessage msg;

        try {
            if (selected.getId() == null) {
                getFacade().create(selected);
            } else {
                getFacade().edit(selected);
            }
            msg = new FacesMessage(FacesMessage.SEVERITY_INFO, "Guardado", "Se ha guardado la información correctamente");
            RequestContext context = RequestContext.getCurrentInstance();
            context.addCallbackParam("success", true);
        } catch (Exception ex) {
            msg = new FacesMessage(FacesMessage.SEVERITY_ERROR, "Error al intentar guardar", "A ocurrido un error");
        }
        FacesContext.getCurrentInstance().addMessage(null, msg);
    }

    /**
     * Permite eliminar la entidad seleccionada.
     *
     * @param event
     */
    public void remove(ActionEvent event) {
        if (selected.getId() != null) {
            getFacade().remove(selected);
            FacesMessage msg = new FacesMessage(FacesMessage.SEVERITY_INFO, "Eliminado", "Se ha eliminado correctamente");
            FacesContext.getCurrentInstance().addMessage(null, msg);
            disableButtons = true;
        }
    }

    /**
     * Permite seleccionar la entidad al hacer click sobre el elemento de la
     * fila.
     *
     * @param event
     */
    public void onRowSelect(SelectEvent event) {
        FacesMessage message = new FacesMessage("A seleccionado", event.getObject().toString());
        FacesContext.getCurrentInstance().addMessage(null, message);
        disableButtons = false;
    }

    /**
     * Permite re-seleccionar la entidad al hacer click sobre el elemento de la
     * fila.
     *
     * @param event
     */
    public void onDblSelect(SelectEvent event) {
        FacesContext context = FacesContext.getCurrentInstance();
        Flash flash = context.getExternalContext().getFlash();
        flash.put("selected", (T) event.getObject());
        disableButtons = false;
    }

    /**
     * Método que sera llamado al momento de editar sobre el botón de edición en
     * la barra de herramientas
     *
     * @param event
     */
    public void editEvent(ActionEvent event) {
        titleDialog = "Editar " + selected.getEntityName();
    }

    /**
     * Método que sera llamado al momento de editar sobre el botón de edición en
     * la barra de herramientas
     *
     * @param event
     */
    public void newEvent(ActionEvent event) {
        try {
            selected = entity.newInstance();
            titleDialog = "Nuevo " + selected.getEntityName();
            disableButtons = true;
        } catch (InstantiationException ex) {
            Logger.getLogger(ControllerFacade.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (IllegalAccessException ex) {
            Logger.getLogger(ControllerFacade.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        }
    }

    public String getEntityName() {
        if (entityName == null) {
            try {
                entityName = ((EntityFacade) entity.newInstance()).getEntityName();
            } catch (InstantiationException ex) {
                Logger.getLogger(ControllerFacade.class.getName()).log(Level.SEVERE, null, ex);
            } catch (IllegalAccessException ex) {
                Logger.getLogger(ControllerFacade.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        return entityName;
    }

    /**
     * Entidad que maneja las distintas operaciones sobre base de datos de la
     * entidad.
     *
     * @return
     */
    public abstract AbstractFacade<T> getFacade();
}
